package com.lancoo.ccas52.arrangecourse.coursescheduling.assignlist;

import com.lancoo.ccas52.arrangecourse.entities.RoomUnitResult;
import com.lancoo.ccas52.arrangecourse.entities.RoomUnits;
import com.lancoo.ccas52.arrangecourse.entities.TeachingClassUnit;
import com.lancoo.ccas52.arrangecourse.entities.TimeslotRoom;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 按照教室容量分配教学班排课单元
 * @Author Fortysun
 * @Date 2024/1/25 16:51
 **/
@Slf4j
public class SpecifiedRoomTeachingClassUnit {
    /***
     * 将同一教室类型的数据进行分组
     * 要做到的效果是，：总共2间教室，一个容量是100，一个是80
     * 那么capacity=100的教室，存放的排课单元的人数是大于80，小于等于100
     * @param teachingClassUnitList
     * @param timeslotRoomList
     * @return
     */
    public RoomUnitResult start(LinkedList<TeachingClassUnit> teachingClassUnitList,
                                LinkedList<TimeslotRoom> timeslotRoomList) {
        //将指定类型的场地，对应的列表，以容量大小为key，转换为map
        Map<Integer, LinkedList<TimeslotRoom>> timeslotRoomMap = getTimeslotRoomMapByCapacity(timeslotRoomList);
        //将指定教学班排课单元对应的列表，以学生人数为key，转换为map
        Map<Integer, LinkedList<TeachingClassUnit>> teachingClassMap = getTeachingClassUnitMapByCapacity(teachingClassUnitList);
        RoomUnitResult roomUnitResult = new RoomUnitResult();

        //定义用于配对的教室、教学班排课单元分组信息
        LinkedList<RoomUnits> roomUnitsList = new LinkedList<>();

        if (timeslotRoomMap != null
                && !timeslotRoomMap.isEmpty()) {
            //获取key的列表，其实就是教室容量的列表
            List<Integer> capacityList = new ArrayList<>(timeslotRoomMap.keySet());
            //对列表，按照从小到大，进行排序
            capacityList.sort(Comparator.naturalOrder());
            for (int i = 0; i < capacityList.size(); i++) {
                //获取当前遍历的教室的容量
                Integer curCapacity = capacityList.get(i);
                //定义访问教学班排课单元map的迭代器
                Iterator<Map.Entry<Integer, LinkedList<TeachingClassUnit>>> iterator = teachingClassMap.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<Integer, LinkedList<TeachingClassUnit>> entry = iterator.next();
                    Integer teachingClassSize = entry.getKey();
                    LinkedList<TeachingClassUnit> unitsList = entry.getValue();
                    //如果是最小容量的教室
                    if (i == 0) {
                        //如果教学班人数小于等于教室容量
                        if (teachingClassSize <= curCapacity) {
                            //生成教室、排课单元对象，供后面算法进行分配
                            RoomUnits roomUnits = new RoomUnits(curCapacity, timeslotRoomMap.get(curCapacity), unitsList);
                            //将生成的对象加入列表
                            roomUnitsList.add(roomUnits);
                            //从map中移除对应的教学班排课单元键值对
                            iterator.remove();
                            log.info("SpecifiedRoomTeachingClassUnit.start--教室容量为：" + curCapacity
                                    + "的教室课时分组数量为：" + timeslotRoomMap.get(curCapacity).size()
                                    + "待分配的教学班排课单元数量为：" + unitsList.size());
                        }
                    } else {//大于零
                        //获取上一次遍历的教室的容量
                        Integer preCapacity = capacityList.get(i-1);
                        if (teachingClassSize <= curCapacity && teachingClassSize > preCapacity) {
                            //生成教室、排课单元对象，供后面算法进行分配
                            RoomUnits roomUnits = new RoomUnits(curCapacity, timeslotRoomMap.get(curCapacity), unitsList);
                            //将生成的对象加入列表
                            roomUnitsList.add(roomUnits);
                            //从map中移除对应的教学班排课单元键值对
                            iterator.remove();
                            log.info("SpecifiedRoomTeachingClassUnit.start--教室容量为：" + curCapacity
                                    + "的教室课时分组数量为：" + timeslotRoomMap.get(curCapacity).size()
                                    + "教学班人数处于" + curCapacity + "和" + preCapacity + "之间的，"
                                    + "待分配的教学班排课单元数量为：" + unitsList.size());
                        }
                    }
                }
            }
            //将编排好的数据，放入返回结果对象
            roomUnitResult.setRoomUnitsList(roomUnitsList);
            //处理剩余的教室课时分组
            if (!timeslotRoomMap.isEmpty()) {
                LinkedList<TimeslotRoom> residueRoomList = timeslotRoomMap.values()
                        .stream()
                        .flatMap(Collection::stream)
                        .collect(Collectors.toCollection(LinkedList::new));
                if (residueRoomList != null && !residueRoomList.isEmpty()) {
                    roomUnitResult.setResidueRoomList(residueRoomList);
                    log.info("SpecifiedRoomTeachingClassUnit.start--剩余待分配的教室课时分组数量为：" + residueRoomList.size());
                }
            }
            //处理剩余的教学班排课单元
            if (!teachingClassMap.isEmpty()) {
                LinkedList<TeachingClassUnit> unitList = teachingClassMap.values()
                        .stream()
                        .flatMap(Collection::stream)
                        .collect(Collectors.toCollection(LinkedList::new));
                if (unitList != null && !unitList.isEmpty()) {
                    roomUnitResult.setResidueUnitList(unitList);
                    log.info("SpecifiedRoomTeachingClassUnit.start--剩余待分配的教学班排课单元数量为：" + unitList.size());
                }
            }
        }

        //释放内存
        if (timeslotRoomMap != null
                && !timeslotRoomMap.isEmpty()) {
            teachingClassMap.clear();
            teachingClassMap = null;
        }
        if (teachingClassMap != null
                && !teachingClassMap.isEmpty()) {
            teachingClassMap.clear();
            teachingClassMap = null;
        }

        return roomUnitResult;
    }

    /**
     * 将教室课时分组信息列表，转换成以capacity为key的map对象
     * @param timeslotRoomList 指定教室类型的教室课时分组信息列表
     * @return
     */
    private Map<Integer, LinkedList<TimeslotRoom>> getTimeslotRoomMapByCapacity(LinkedList<TimeslotRoom> timeslotRoomList) {

        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //按教室容量，将教室课时分组列表数据，进行分组
            Map<Integer, LinkedList<TimeslotRoom>> timeslotRoomMap = timeslotRoomList
                    .stream()
                    .collect(Collectors.groupingBy(TimeslotRoom::getCapacity,Collectors.toCollection(LinkedList::new)));
            return timeslotRoomMap;
        }
        log.info("SpecifiedRoomTeachingClassUnit--getTimeslotRoomMapByCapacity: 没有需要转换成，以capacity为key的教室课时分组Map,的分组列表信息~！！");
        return null;
    }

    /**
     * 将教学班排课单元列表，转换成以teachingClassSize为key的map对象
     * @param teachingClassUnitList 指定类型的，教学班排课单元列表
     * @return
     */
    private Map<Integer, LinkedList<TeachingClassUnit>> getTeachingClassUnitMapByCapacity(LinkedList<TeachingClassUnit> teachingClassUnitList) {

        if (teachingClassUnitList != null && !teachingClassUnitList.isEmpty()) {
            //按教学班人数，将教学班排课单元列表数据，进行分组
            Map<Integer, LinkedList<TeachingClassUnit>> teachingClassUnitMap = teachingClassUnitList
                    .stream()
                    .collect(Collectors.groupingBy(TeachingClassUnit::getTeachingClassSize,Collectors.toCollection(LinkedList::new)));
            return teachingClassUnitMap;
        }
        log.info("SpecifiedRoomTeachingClassUnit--getTeachingClassUnitMapByCapacity: 没有需要转换成，以teachingClassSize为key的教学班排课单元Map，的列表信息~！！");
        return null;
    }
}
